#pragma once
#include <vector>
#include <iostream>
#include <fstream>

#include "Vertex4f.h"
#include "IDXDrawable.h"
#include "Display.h"
#include "Triangle.h"


#include "BufferStructs.h"

class Mesh:public IDXVertBuffer,
		   public IDXColorBuffer
{
	std::vector<Vertex4f> mVertexList;
	std::vector<Triangle> mTriangleList;

	LPDIRECT3DVERTEXBUFFER9		mVertexBuffer;
	LPDIRECT3DVERTEXBUFFER9		mColorBuffer;

	void Clear(void)
	{
		mVertexList.clear();
		mTriangleList.clear();
	}
	
public:
	Mesh(void):mColorBuffer(0),mVertexBuffer(0){}
	virtual ~Mesh(void){Clear();} 

	// Interface IDXVertexBuffer
	virtual LPDIRECT3DVERTEXBUFFER9 GetVertexBuffer(){
		return mVertexBuffer;
	}
	virtual HRESULT UpdateVertexBufferFromVertices(CComPtr<IDirect3DDevice9> &mDevice)
	{
		if(mVertexBuffer) mVertexBuffer->Release();

		unsigned int numTriangle = mTriangleList.size();
		unsigned int numVertices = numTriangle * 3;
		mDevice->CreateVertexBuffer(numVertices * sizeof(Vertex),   
							   0, 0,   
							   D3DPOOL_DEFAULT, &mVertexBuffer, NULL);
		Vertex *pVertices = NULL;
		mVertexBuffer->Lock(0,sizeof(Vertex) * numVertices,(void**)&pVertices,NULL);
		for(unsigned int i = 0; i < numTriangle; i++) {
			unsigned int indexV1, indexV2, indexV3;
			indexV1 = mTriangleList[i].GetV1();
			indexV2 = mTriangleList[i].GetV2();
			indexV3 = mTriangleList[i].GetV3();

			(pVertices + i * 3)->x = mVertexList[indexV1].GetX();
			(pVertices + i * 3)->y = mVertexList[indexV1].GetY();
			(pVertices + i * 3)->z = mVertexList[indexV1].GetZ();

			(pVertices + i * 3 + 1)->x = mVertexList[indexV2].GetX();
			(pVertices + i * 3 + 1)->y = mVertexList[indexV2].GetY();
			(pVertices + i * 3 + 1)->z = mVertexList[indexV2].GetZ();

			(pVertices + i * 3 + 2)->x = mVertexList[indexV3].GetX();
			(pVertices + i * 3 + 2)->y = mVertexList[indexV3].GetY();
			(pVertices + i * 3 + 2)->z = mVertexList[indexV3].GetZ();

		}
		mVertexBuffer->Unlock();
		return S_OK;
	}

	// Interface IDXColorBuffer
	virtual LPDIRECT3DVERTEXBUFFER9 GetColorBuffer()
	{
		return mColorBuffer;
	}
	virtual HRESULT UpdateColorBufferFromVertices(CComPtr<IDirect3DDevice9> &mDevice)
	{
		if(mColorBuffer) mColorBuffer->Release();

		unsigned int numTriangle = mTriangleList.size();
		unsigned int numVertices = numTriangle * 3;
		mDevice->CreateVertexBuffer(numVertices * sizeof(Color),   
							   0, 0,   
							   D3DPOOL_DEFAULT, &mColorBuffer, NULL);
		Color *pColors = NULL;
		mColorBuffer->Lock(0,sizeof(Color) * numTriangle * 3,(void**)&pColors,NULL);
		for(unsigned int i = 0; i < numTriangle; i++) {
			unsigned int indexV1, indexV2, indexV3;
			indexV1 = mTriangleList[i].GetV1();
			indexV2 = mTriangleList[i].GetV2();
			indexV3 = mTriangleList[i].GetV3();

			(pColors + i * 3)->color = D3DCOLOR_COLORVALUE(
				mVertexList[indexV1].GetR(), 
				mVertexList[indexV1].GetG(), 
				mVertexList[indexV1].GetB(),
				mVertexList[indexV1].GetA());
			(pColors + i * 3 + 1)->color = D3DCOLOR_COLORVALUE(
				mVertexList[indexV2].GetR(), 
				mVertexList[indexV2].GetG(), 
				mVertexList[indexV2].GetB(),
				mVertexList[indexV2].GetA());
			(pColors + i * 3 + 2)->color = D3DCOLOR_COLORVALUE(
				mVertexList[indexV3].GetR(), 
				mVertexList[indexV3].GetG(), 
				mVertexList[indexV3].GetB(),
				mVertexList[indexV3].GetA());
		}
		mColorBuffer->Unlock();
		return S_OK;
	}

	void AddVertex(Vertex4f v){mVertexList.push_back(v);}
	void AddTriangle(Triangle t){mTriangleList.push_back(t);}
	
	/// Maybe implement a Helper loader class
	static HRESULT LoadFromFile(std::string filename, Mesh &m)
	{
		std::string fileInfo;
		unsigned int nVertices, nTriangles;
		std::ifstream file;
		file.open(filename.c_str(), std::ios::in);
		std::getline(file, fileInfo);
		if(fileInfo != "mw 1.0")
			return S_FALSE;
		file >> nVertices;
		for(unsigned int i=0;i<nVertices;i++) {
			if(file.eof())
				return S_FALSE;
			Vertex4f v;
			file >> v;
			m.AddVertex(v);
		}
		file >> nTriangles;
		for(unsigned int i=0;i<nTriangles;i++) {
			if(file.eof())
				return S_FALSE;
			Triangle t;
			file >> t;
			m.AddTriangle(t);
		}
		file.close();
		return S_OK;
	}
};
